﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Rappelz.GameServer.Network.GameClient;
using Rappelz.GameServer.Network;
using Rappelz.GameServer.Database;

namespace Rappelz.GameServer
{
    public interface ArRegionFunctor
    {
        void run(ArRegion region);
    }

    public interface BaseObjectFunctor
    {
        void run(BaseObject client);
    }

    public interface QMQuestFunctor
    {
        bool run(Quest quest);
    }

    public interface NPCQuestFunctor
    {
        bool run(Player pPlayer, QuestLink link_info);
    }

    public interface SkillPtrFunctor
    {
        void onSkill(Skill skill);
    }

    public interface SkillFunctor
    {
        void onSkill(int sid, int skill_id, int base_skill_level, int current_skill_level, uint total_cool_time, uint remain_cool_time);
    }

    public interface SkillTargetFunctor
    {
        bool onCreature(Skill pSkill, uint t, Creature pCaster, Creature pTarget);
    }


    public interface StateFunctor
    {
        void onState(State state);
    }

    public interface PartyFunctor
    {
        bool run(uint handle);
    }

    public interface GuildFunctor
    {
        bool run(uint handle);
    }

    public class ArcadiaServerSetMultipleMoveArRegionFunctor : ArRegionFunctor
    {
        public uint nCnt;
        public BaseObject obj;

        public void run(ArRegion region)
        {
            SendMoveMessageArObjectFunctor fn = new SendMoveMessageArObjectFunctor();
            fn.obj = obj;
            this.nCnt += region.DoEachClient(fn);
        }
    }


    public class ArcadiaServerenterProcArRegionFunctor : ArRegionFunctor
    {
        public bool bIsClientObject;
        public bool bIsSent;
        public BaseObject obj;

        public void run(ArRegion region)
        {
            if (region != null)
            {
                ArcadiaServerSendEnterMessageEachOtherArObjectFunctor fn1 = new ArcadiaServerSendEnterMessageEachOtherArObjectFunctor();
                fn1.obj = this.obj;
                if (region.DoEachClient(fn1) != 0)
                    bIsSent = true;
                if (obj.m_nArObjectType == 2)
                {
                    SendEnterMsgArObjectFunctor fn2 = new SendEnterMsgArObjectFunctor();
                    fn2.obj = obj;
                    region.DoEachStaticObject(fn2);
                    region.DoEachMovableObject(fn2);
                }
            }
        }
    }

    public class ArcadiaServerAddObjectArRegionFunctor : ArRegionFunctor
    {
        public bool bIsClientObject;
        public bool bIsSent;
        public BaseObject obj;

        public void run(ArRegion region)
        {
            ArcadiaServerSendEnterMessageEachOtherArObjectFunctor fn = new ArcadiaServerSendEnterMessageEachOtherArObjectFunctor();
            fn.obj = this.obj;
            region.DoEachClient(fn);

            if (this.obj.m_nArObjectType == 2)
            {
                SendEnterMsgArObjectFunctor fn2 = new SendEnterMsgArObjectFunctor();
                fn2.obj = this.obj;
                region.DoEachStaticObject(fn2);
                region.DoEachMovableObject(fn2);
            }
        }
    }

    public class ArcadiaServerSetMoveArRegionFunctor : ArRegionFunctor
    {
        public uint nCnt;
        public BaseObject obj;

        public void run(ArRegion region)
        {
            SendMoveMessageArObjectFunctor fn = new SendMoveMessageArObjectFunctor();
            fn.obj = this.obj;
            this.nCnt += region.DoEachClient(fn);
        }
    }

    public class ArcadiaServerBroadcastSenderArRegionFunctor : ArRegionFunctor
    {
        public BaseObjectFunctor pFo;

        public void run(ArRegion region)
        {
            region.DoEachClient(this.pFo);
        }
    }

    public class onGetRegionInfoArRegionFunctor : ArRegionFunctor
    {
        public BaseObject obj;

        public void run(ArRegion region)
        {
            SendEnterMsgArObjectFunctor fn = new SendEnterMsgArObjectFunctor();
            fn.obj = this.obj;

            region.DoEachClient(fn);
            region.DoEachMovableObject(fn);
            region.DoEachStaticObject(fn);
            region.DoEachClient(fn);
        }
    }

    public class ArcadiaServerSendEnterMessageEachOtherArObjectFunctor : BaseObjectFunctor
    {
        public uint nCnt;
        public BaseObject obj;

        public void run(BaseObject client)
        {
            if (!ReferenceEquals(obj, client))
            {
                Messages.sendEnterMessage(client, obj, false);
                if (obj.m_nArObjectType == 2 )
                    Messages.sendEnterMessage(obj, client, false);
            }
        }
    }

    public class ArcadiaServerMessageSenderArObjectFunctor : BaseObjectFunctor
    {
        public RappelzIntf pIntf;
        public PacketOut msg;   

        public void run(BaseObject client)
        {
            this.pIntf.SendGameMessage(client, msg);
        }
    }

    public class SendMoveMessageArObjectFunctor : BaseObjectFunctor
    {
        public BaseObject obj;

        public void run(BaseObject client)
        {
            RappelzServer.m_Intf.SendMoveMessage(client, obj);
        }
    }


    public class SendEnterMsgArObjectFunctor : BaseObjectFunctor
    {
        public BaseObject obj;

        public void run(BaseObject client)
        {
            Messages.sendEnterMessage(obj,client,false);
            if (obj.m_nArObjectType == 1)
            {
                SchedulerObject.Priority priority;
                obj.bIsNearClient = true;
                if (obj.pending_priority == SchedulerObject.Priority.Null)
                    priority = obj.priority;
                else
                    priority = obj.pending_priority;
                if ((int)priority < 3 )
                {
                    RappelzServer.Instance.SetObjectPriority(obj, SchedulerObject.Priority.Normal);
                }
            }

        }
    }

    public class SendChatMessageWithLockArObjectFunctor : BaseObjectFunctor
    {
        public BaseObject obj;
        public PacketOut msg;

        public void run(BaseObject client)
        {
            Player player = client as Player;
            if(player != null)
            {
                player.Connection.SendTCP(msg);
            }
        }
    }

/*
UserDefinedType: _SendEnterMsg
BaseClass      :   ArObjectFunctor, offset = 0x0
VTable         :     , Type:  *
Function       :     public void operator()(struct ArObject *)
Function       :     public void ArObjectFunctor(const struct ArObjectFunctor &)
Function       :     public void ArObjectFunctor()
Function       :     public struct ArObjectFunctor & operator=(const struct ArObjectFunctor &)

Function       :   public void _SendEnterMsg(const struct _SendEnterMsg &)
Function       :   public void _SendEnterMsg(struct ArObject *)
Function       :   public void _SendEnterMsg::operator()(struct ArObject *)
Data           :   this+0x4, Member, Type: const struct ArObject *, pClient
Function       :   public struct _SendEnterMsg & operator=(const struct _SendEnterMsg &)
*/

// UserDefinedType: _SendForceMoveMessage
// BaseClass      :   ArObjectFunctor, offset = 0x0
// VTable         :     , Type:  *
// Function       :     public void operator()(struct ArObject *)
// Function       :     public void ArObjectFunctor(const struct ArObjectFunctor &)
// Function       :     public void ArObjectFunctor()
// Function       :     public struct ArObjectFunctor & operator=(const struct ArObjectFunctor &)
// 
// Function       :   public void _SendForceMoveMessage(const struct _SendForceMoveMessage &)
// Function       :   public void _SendForceMoveMessage(const struct ArObject *)
// Function       :   public void _SendForceMoveMessage::operator()(struct ArObject *)
// Data           :   this+0x4, Member, Type: const struct ArObject *, pWho
// Function       :   public struct _SendForceMoveMessage & operator=(const struct _SendForceMoveMessage &)

    public class PlayerSaveQuestFunctor : QMQuestFunctor
    {
        public Player m_pPlayer;

        public PlayerSaveQuestFunctor(Player p)
        {
            m_pPlayer = p;
        }

        public bool run(Quest quest)
        {
            if (quest.m_bIsNeedUpdateToDB)
            {
                m_pPlayer.DBQuery(new DB_UpdateQuest(m_pPlayer, m_pPlayer.m_nUID,quest.m_Instance.nId, quest.GetStatus(0),quest.GetStatus(1),quest.GetStatus(2)
                    ,quest.GetStatus(3),quest.GetStatus(4),quest.GetStatus(5), (int)quest.m_Instance.nProgress,quest.m_Instance.nTime));
                quest.m_bIsNeedUpdateToDB = false;
            }
            return true;
        }
    }

    public class SendQuestListFunctor : QMQuestFunctor
    {
        public Player m_pPlayer;
        public PacketOut m_packet;

        public SendQuestListFunctor(Player p, PacketOut packet)
        {
            m_pPlayer = p;
            m_packet = packet;
        }

        public bool run(Quest quest)
        {
//             TS_SC_QUEST_LIST::TS_QUEST_INFO quest_info; // [sp+8h] [bp-38h]@1
// Data           :   this+0x0, Member, Type: int, code
// Data           :   this+0x4, Member, Type: int, nStartID
// Data           :   this+0x8, Member, Type: int[0x6], nValue
// Data           :   this+0x20, Member, Type: int[0x6], nStatus
            int i;

            m_packet.WriteInt32(quest.m_Instance.Code);
            m_packet.WriteInt32(quest.m_Instance.nStartID);

            if (Quest.IsRandomQuest(quest.m_Instance.Code))
            {
                m_packet.WriteInt32(quest.GetRandomKey(0));
                m_packet.WriteInt32(quest.GetRandomValue(0));
                m_packet.WriteInt32(quest.GetRandomKey(1));
                m_packet.WriteInt32(quest.GetRandomValue(1));
                m_packet.WriteInt32(quest.GetRandomKey(2));
                m_packet.WriteInt32(quest.GetRandomValue(2));
            }
            else
            {
                for (i = 0; i < 6; ++i)
                {
                    m_packet.WriteInt32(quest.m_QuestBase.nValue[i]);
                }
            }

            for (i = 0; i < 6; ++i)
            {
                m_packet.WriteInt32(quest.m_Instance.nStatus[i]);
            }

            m_packet.WriteByte((byte)(quest.IsFinishable() ? 2 : 1));
            m_packet.WriteUInt32(quest.m_Instance.nTime);
            return true;
        }
    }

    public class PlayerSaveSkillFunctor : SkillPtrFunctor
    {
        public Creature pOwner;
        public uint t;
        public bool bSaveAll;
        public PlayerSaveSkillFunctor(Creature _pOwner, bool _bSaveAll)
        {
            pOwner = _pOwner;
            bSaveAll = _bSaveAll;
        }

        public void onSkill(Skill skill)
        {
/*
    int v2; // ebp@0
    StructPlayer::Save::__l29::mySkillFunctor *v3; // edi@1
    int v4; // esi@1
    int v5; // eax@1
    unsigned int v6; // ecx@6
    unsigned int v7; // eax@6
    signed int v8; // eax@7
    void *v9; // eax@12
    unsigned int v10; // ecx@13
    int v11; // eax@13
    int v12; // ecx@14
    GameDBManager::DBProc *v13; // eax@16
    StructPlayer *v14; // ecx@18
    void *v15; // eax@20
    unsigned int v16; // ecx@21
    int v17; // eax@21
    int v18; // ecx@22
    GameDBManager::DBProc *v19; // eax@24
    StructSummon *v20; // ecx@26

    v3 = this;
    v4 = *(v2 + 8);
    v5 = *(v4 + 8);
    if ( v5 != -1 && v5 != -2 && v5 != -3 && v5 != -4 && v5 != -5 )
    {
        v6 = this->t;
        v7 = *(v4 + 72);
        v8 = v7 <= v6 ? 0 : v7 - v6;
        if ( v8 || v3->bSaveAll )
        {
            if ( (v3->pOwner->baseclass_0.baseclass_0.baseclass_0.vfptr[1].onProcess)() )
            {
                v9 = GameDBManager::DBProc::operator new(0x170u);
                *(v2 + 8) = v9;
                *(v2 - 4) = 0;
                if ( v9 )
                {
                    v10 = v3->t;
                    v11 = *(v4 + 72);
                    if ( v11 <= v10 )
                        v12 = 0;
                    else
                        v12 = v11 - v10;
                    DB_UpdateSkill::DB_UpdateSkill(*(v2 + 8), v3->pOwner, *(v4 + 8), *(v4 + 16) + *(v4 + 20), v12);
                }
                else
                {
                    v13 = 0;
                }
                v14 = v3->pOwner;
                *(v2 - 4) = -1;
                StructPlayer::DBQuery(v14, v13);
            }
            else
            {
                if ( (v3->pOwner->baseclass_0.baseclass_0.baseclass_0.vfptr[2].GetHandle)() )
                {
                    v15 = GameDBManager::DBProc::operator new(0x170u);
                    *(v2 + 8) = v15;
                    *(v2 - 4) = 1;
                    if ( v15 )
                    {
                        v16 = v3->t;
                        v17 = *(v4 + 72);
                        if ( v17 <= v16 )
                            v18 = 0;
                        else
                            v18 = v17 - v16;
                        DB_UpdateSkill::DB_UpdateSkill(*(v2 + 8), v3->pOwner, *(v4 + 8), *(v4 + 16) + *(v4 + 20), v18);
                    }
                    else
                    {
                        v19 = 0;
                    }
                    v20 = v3->pOwner;
                    *(v2 - 4) = -1;
                    StructSummon::DBQuery(v20, v19);
                }
            }
        }
    }
*/
        }
    }

    public class ShowQuestMenuNPCQuestFunctor : NPCQuestFunctor
    {
        public int m_QuestProgress;
        public List<int> vRandomQuestCode = new List<int>();

        public ShowQuestMenuNPCQuestFunctor(int p)
        {
            m_QuestProgress = p;
        }

        public bool run(Player pPlayer, QuestLink link_info)
        {
            string szBuf;
            string szButtonName;

            QuestBaseServer qbs = Quest.GetQuestBase(link_info.code);

            if (qbs.nType == QuestBase.QuestType.RandomKillIndividual || qbs.nType == QuestBase.QuestType.RandomCollect)
            {
                this.vRandomQuestCode.Add(link_info.code);
            }
            if((qbs.nType != QuestBase.QuestType.RandomKillIndividual && qbs.nType != QuestBase.QuestType.RandomCollect) || (m_QuestProgress != 0))
            {
                int qpid = link_info.nStartTextId;
                if (m_QuestProgress == 1)
                    qpid = link_info.nInProgressTextId;
                else if (m_QuestProgress == 2)
                    qpid = link_info.nEndTextId;
                szBuf = String.Format("quest_info( {0}, {1} )", link_info.code, qpid);
                szButtonName = String.Format("QUEST|{0}|{1}", qbs.nQuestTextId,(int)m_QuestProgress);
                pPlayer.AddDialogMenu(szButtonName, szBuf);
            }
            return true;
        }
    }

    public class addEXPPartyFunctor1 : PartyFunctor
    {
        public bool run(uint handle)
        {
            this.nTotalCount++;
            Player player = Player.get(handle) as Player;

            if (player != null)
            {
                if (player.bIsInWorld )
                {
                    if (this.layer == player.m_layer)
                    {
                        if (this.pos.GetDistance(player.mv) <= 500.0f)
                        {
                            this.pOneManPlayer = player;
                            int l = player.GetLevel();
                            if (this.nMaxLevel < l)
                                this.nMaxLevel = l;
                            if (this.nMinLevel > l)
                                this.nMinLevel = l;
                            this.nTotalLevel += l;
                            this.nCount++;
                        }
                    }
                }
            }
            return true;
        }

        public ArPosition pos;// Data           :   this+0x4, Member, Type: struct ArPosition, 
        public byte layer;// Data           :   this+0x14, Member, Type: unsigned char, 
        public uint t;// Data           :   this+0x18, Member, Type: unsigned long, 
        public int nTotalCount;// Data           :   this+0x1C, Member, Type: int, 
        public int nCount;// Data           :   this+0x20, Member, Type: int, 
        public int nMaxLevel;// Data           :   this+0x24, Member, Type: int, 
        public int nMinLevel;// Data           :   this+0x28, Member, Type: int, 
        public int nTotalLevel;// Data           :   this+0x2C, Member, Type: int, 
        public Player pOneManPlayer;// Data           :   this+0x30, Member, Type: struct StructPlayer *, pOneManPlayer
    }

    public class addEXPPartyFunctor2 : PartyFunctor
    {
        public bool run(uint handle)
        {
            float fLevelPenalty;
            float fJP;
            float fEXP;
            Player player = Player.get(handle) as Player;

            if (player != null)
            {
                float ratio = player.GetLevel() / this.nTotalLevel;
                fEXP = this.nSharedEXP * ratio;
                fJP = this.nSharedJP * ratio;
                fLevelPenalty = 1.0f - 0.1f * ((float)(this.nMaxLevel - player.GetLevel()) * 0.1f);

                fLevelPenalty = Math.Max(0.0f, fLevelPenalty >= 1.0f ? 1.0f : fLevelPenalty);

                fEXP = (fLevelPenalty * fEXP) * GameRule.fPartyEXPRate;
                fJP = (fLevelPenalty * fJP) * GameRule.fPartyEXPRate;
                if (fEXP < 1.0f)
                    fEXP = 1.0f;
                GameContent.addEXP(this.pCorpse, player, fEXP, fJP);
            }
            return true;
        }

        public Creature pCorpse;// Data           :   this+0x4, Member, Type: struct StructCreature *, pCorpse
        public int nMaxLevel;// Data           :   this+0x8, Member, Type: int, 
        public int nTotalLevel;// Data           :   this+0xC, Member, Type: int, 
        public int nSharedEXP;// Data           :   this+0x10, Member, Type: int, 
        public int nSharedJP;// Data           :   this+0x14, Member, Type: int, 
    }


    public class partyPCBangBonusChecker : PartyFunctor
    {
        public bool run(uint handle)
        {
            if (!this.m_bPremiumPCBang)
            {
                Player p = Player.get(handle) as Player;
                if (p != null && p.bIsInWorld)
                {
                    if (this.m_posKiller.GetDistance(p.mv) <= 500.0f)
                    {
                        if (p.GetPCBangMode() == 2 )
                            this.m_bPremiumPCBang = true;
                    }

                }
            }
            return true;
        }

        public Creature pCorpse;// Data           :   this+0x4, Member, Type: struct StructCreature *, pCorpse
        public int nMaxLevel;// Data           :   this+0x8, Member, Type: int, 
        public int nTotalLevel;// Data           :   this+0xC, Member, Type: int, 
        public int nSharedEXP;// Data           :   this+0x10, Member, Type: int, 
        public int nSharedJP;// Data           :   this+0x14, Member, Type: int, 
        public ArPosition m_posKiller;
        public bool m_bPremiumPCBang;
    }

    public class BroadcastStatusMessageArObjectFunctor : BaseObjectFunctor
    {
        public RappelzIntf pIntf;
        public Creature pCreature;

        public void run(BaseObject client)
        {
            PacketOut msg = new PacketOut((ushort)ClientOutPackets.StatusChange);
            msg.WriteUInt32(pCreature.m_hHandle);
            msg.WriteUInt32(Messages.GetStatusCode(pCreature, client as Player));
            this.pIntf.SendGameMessage(client, msg);
        }
    }

    public class BroadcastStatusMessageArRegionFunctor : ArRegionFunctor
    {
        public BaseObjectFunctor pFo;

        public void run(ArRegion region)
        {
            if (region != null)
            {
                region.DoEachClient(this.pFo);
            }
        }
    }

    public class EnumMovableObjectArRegionFunctor : ArRegionFunctor
    {
        public class SubFunctor : BaseObjectFunctor
        {
            public void run(BaseObject client)
            {
                ArPosition c_pos = client.GetCurrentPosition(this.pParent.t);

                if (c_pos.x >= this.pParent.left && c_pos.x <= this.pParent.right && c_pos.y >= this.pParent.top && c_pos.y <= this.pParent.bottom)
                {
                    if (this.pParent.range > c_pos.GetDistance(this.pParent.pos))
                    {
                        this.pParent.pvResult.Add(client.m_hHandle);
                    }
                }
            }

            public EnumMovableObjectArRegionFunctor pParent;
        }

        public BaseObjectFunctor pFo;
        public List<uint> pvResult;
        public uint t;
        public ArPosition pos;
        public float left;
        public float right;
        public float top;
        public float bottom;
        public float range;
        public bool bIncludeClient;
        public bool bIncludeNPC;

        public EnumMovableObjectArRegionFunctor(List<uint> _pvResult, ArPosition _pos, float _range, bool _bIncludeClient, bool _bIncludeNPC)
        {
            this.range = _range;
            this.bIncludeClient = _bIncludeClient;
            this.pos = _pos;
            this.bIncludeNPC = _bIncludeNPC;
            this.left = _pos.x - _range;
            this.right = _pos.x + _range;
            this.top = _pos.y - _range;
            this.bottom = _pos.y + _range;
            this.pvResult = _pvResult;
            this.t = Globals.GetArTime();
        }


        public void run(ArRegion region)
        {
            if (region != null)
            {
                SubFunctor fn = new SubFunctor();
                fn.pParent = this;

                if (this.bIncludeClient)
                {
                    region.DoEachClient(fn);
                }
                if (this.bIncludeNPC)
                {
                    region.DoEachMovableObject(fn);
                }
            }
        }
    }

    public class ArcadiaServerDeleteObjectArRegionFunctor : ArRegionFunctor
    {
        public BaseObject pObject;

        public void run(ArRegion region)
        {
            if (region != null)
            {
                SendLeaveMsgArObjectFunctor fn = new SendLeaveMsgArObjectFunctor();
                fn.obj = this.pObject;
                region.DoEachClient(fn);
            }
        }
    }

    public class SendLeaveMsgArObjectFunctor : BaseObjectFunctor
    {
        public BaseObject obj;

        public void run(BaseObject client)
        {
            if (client.m_nArObjectType == 2)
                RappelzServer.m_Intf.SendLeaveMessage(client, obj);
        }
    }

    public class SendNPCStatusInVisibleRangeArRegionFunctor : ArRegionFunctor
    {
        public BaseObjectFunctor pFo;

        public void run(ArRegion region)
        {
            if (region != null)
            {
                region.DoEachMovableObject(pFo);
            }
        }
    }

    public class SendNPCStatusInVisibleRangeArObjectFunctor : BaseObjectFunctor
    {
        public Player pPlayer;
        public RappelzIntf pIntf;

        public void run(BaseObject client)
        {
            if (pPlayer == null || pPlayer.Connection == null)
                return;

            Creature cr = GameObject.get(client.m_hHandle) as Creature;
            if (cr != null && cr.IsNPC())
            {
                PacketOut pak = new PacketOut((ushort)ClientOutPackets.StatusChange);
                pak.WriteUInt32(cr.m_hHandle);
                pak.WriteUInt32(Messages.GetStatusCode(cr, this.pPlayer));
                this.pIntf.SendGameMessage(this.pPlayer, pak);
            }
        }
    }

    public class SendSkillMessageSkillFunctor : SkillFunctor
    {
        public uint cnt;    // Data           :   this+0x4, Member, Type: unsigned int, cnt
        public List<SkillListPacket.SkillInfo> pSkills;
// Data           :   this+0x8, Member, Type: char *, pBuf
        public Player pPlayer;// Data           :   this+0xC, Member, Type: const struct StructPlayer *, 

        public SendSkillMessageSkillFunctor(Player p, List<SkillListPacket.SkillInfo> s)
        {
            pPlayer = p;
            pSkills = s;
        }

        public void onSkill(int sid, int skill_id, int base_skill_level, int current_skill_level, uint total_cool_time, uint remain_cool_time)
        {
            SkillListPacket.SkillInfo info = new SkillListPacket.SkillInfo();
            info.skill_id = skill_id;
            info.base_skill_level = (byte)base_skill_level;
            info.current_skill_level = (byte)current_skill_level;
            info.total_cool_time = total_cool_time;
            info.remain_cool_time = remain_cool_time;
            this.cnt++;
            this.pSkills.Add(info);
        }
    }

    public class SendGlobalChatMessagArObjectFunctor : BaseObjectFunctor
    {
        public PacketOut msg;

        public void run(BaseObject client)
        {
            Player player = client as Player;
            if (player != null)
            {
                player.Connection.SendTCP(msg);
            }
        }
    }

    public class PlayerOnApplyStatSkillFunctor : SkillPtrFunctor
    {
//        public uint cnt;    // Data           :   this+0x4, Member, Type: unsigned int, cnt
//        public List<SkillListPacket.SkillInfo> pSkills;
        // Data           :   this+0x8, Member, Type: char *, pBuf
        public Player pPlayer;
        public Summon pSummon;

        public PlayerOnApplyStatSkillFunctor(Player _player)
        {
            pPlayer = _player;
        }

        public void onSkill(Skill skill)
        {
        }
    }

    public class SendGuildInfoFunctor : GuildFunctor
    {
        public List<string> vOnlineMemberList = new List<string>();
        public Player m_pPlayer;

        public bool run(uint handle)
        {
            Player p = Player.get(handle) as Player;
            if (p != null)
            {
                string name = p.GetName();
                this.vOnlineMemberList.Add(name);
                string msg = String.Format("GMEMBER|{0}|{1}|{2}|{3}|{4}|{5}|{6}|{7}|{8}|2", (int)p.m_hHandle, p.GetName(), p.GetLevel(), p.GetJobId(),p.m_nGuildRank,
                    p.GetHPPercentage(), p.GetMPPercentage(), (int)(p.mv.x),(int)(p.mv.y));
                Messages.SendChatMessage(false, 110, "@GUILD", this.m_pPlayer.m_hHandle, msg, 0);

                msg = String.Format("MEMO|{0}|{1}|", p.GetName(),p.m_strGuildMemo);
                Messages.SendChatMessage(false, 110, "@GUILD", this.m_pPlayer.m_hHandle, msg, 0);
            }

            return true;

        }
    }

// UserDefinedType: SendGuildInfo::__l4::myGuildFunctor
// BaseClass      :   GuildManager::GuildFunctor, offset = 0x0
// VTable         :     , Type:  *
// Function       :     public bool operator()(unsigned int)
// Function       :     public void GuildFunctor(const struct GuildManager::GuildFunctor &)
// Function       :     public void GuildFunctor()
// Function       :     public struct GuildManager::GuildFunctor & operator=(const struct GuildManager::GuildFunctor &)
// 
// Function       :   public void myGuildFunctor(const struct SendGuildInfo::__l4::myGuildFunctor &)
// Function       :   public void myGuildFunctor(struct StructPlayer *)
// Function       :   public bool operator()(unsigned int)
    public class FireSkillStateSkillFunctor : SkillTargetFunctor
    {
        public bool onCreature(Skill pSkill, uint t, Creature pCaster, Creature pTarget)
        {
// .text:004C6D96 vStateID        = std::vector<int,std::allocator<int> > ptr -80h
            int nLevel;                     // -36  -24h
            int count;                      // -32  -20h
// .text:004C6D96 code            = dword ptr -18h
            int i;                          // -20  -14h
            bool bResult;                   // -16  -10h
// .text:004C6D96 pSkill          = dword ptr  4
            uint end_time;                  // 8    8
            State.StateCode stateCode;
// .text:004C6D96 t               = dword ptr  0Ch
// .text:004C6D96 pCaster         = dword ptr  10h
// .text:004C6D96 pTarget         = dword ptr  14h
// 
// Data           :   ebp Relative, [00000008], Param, Type: struct StructSkill *, pSkill
// Data           :   ebp Relative, [0000000C], Param, Type: unsigned long, t
// Data           :   ebp Relative, [00000010], Param, Type: struct StructCreature *, pCaster
// Data           :   ebp Relative, [00000014], Param, Type: struct StructCreature *, pTarget
// Data           :   ebp Relative, [FFFFFFF0], Local, Type: bool, bResult
// Data           :   ebp Relative, [00000008], Local, Type: unsigned long, end_time
// Data           :   ebp Relative, [FFFFFFE8], Local, Type: int, nLevel
// Data           :   ebp Relative, [FFFFFFE0], Local, Type: int, count
// Data           :   ebp Relative, [FFFFFFEC], Local, Type: int, i
// Data           :   ebp Relative, [FFFFFFDC], Local, Type: int, nLevel
// Data           :   ebp Relative, [FFFFFFE0], Local, Type: int, i
// Data           :   ebp Relative, [FFFFFFE8], Local, Type: enum StructState::StateCode, code
// Data           :   ebp Relative, [FFFFFFE8], Local, Type: int, i
// Data           :   ebp Relative, [FFFFFFE0], Local, Type: enum StructState::StateCode, code
// Data           :   ebp Relative, [FFFFFFEC], Local, Type: int, i
// Data           :   ebp Relative, [FFFFFFDC], Local, Type: int, nLevel
// Data           :   ebp Relative, [FFFFFFE0], Local, Type: enum StructState::StateCode, code
// Data           :   ebp Relative, [FFFFFF80], Local, Type: class std::vector<int,std::allocator<int> >, vStateID
            bResult = true;
            int chanceRes = 1;

            if (pSkill.m_SkillBase.is_harmful != 0)
            {
                if (pSkill.m_SkillBase.uid == 6008 || pSkill.m_SkillBase.uid == 6009 || pSkill.m_SkillBase.uid == 6010 )
                {
                    if (Constants.s_chip_limit_level[pSkill.m_nRequestedSkillLevel] >= pTarget.GetLevel())
                    {
                        chanceRes = 1;
                    }
                    else 
                    {
                        chanceRes = (10 * (Constants.s_chip_limit_level[pSkill.m_nRequestedSkillLevel] - pTarget.GetLevel() + 10)) - (Globals.GetRandomInt32() % 100);
                    }
                }
                else
                {
                    if (pSkill.m_SkillBase.effect_type == 301
                      || pSkill.m_SkillBase.effect_type == 302
                      || pSkill.m_SkillBase.effect_type == 305
                      || pSkill.m_SkillBase.effect_type == 306
                      || pSkill.m_SkillBase.effect_type == 307
                      || pSkill.m_SkillBase.effect_type == 308
                      || pSkill.m_SkillBase.effect_type == 309 )
                    {
                        chanceRes = (int)((pCaster.m_Attribute.nMagicAccuracy - pCaster.m_Attribute.nMagicAvoid + pSkill.m_SkillBase.GetHitBonus(pSkill.m_nEnhance, pCaster.GetLevel() - pTarget.GetLevel()) + 50) - (Globals.GetRandomInt32() % 100));
                    }
                    else
                    {
                        chanceRes = (pSkill.m_SkillBase.probability_on_hit + pSkill.m_nRequestedSkillLevel * pSkill.m_SkillBase.probability_inc_by_slv) - (Globals.GetRandomInt32() % 100);
                    }
                }
            }

            if (chanceRes <= 0)
            {
                bResult = false;
            }
            else
            {
//                v22 = pSkill.m_nEnhance;
//                v23 = pSkill.m_SkillBase;
                int gss = pSkill.m_SkillBase.GetStateSecond(pSkill.m_nRequestedSkillLevel, pSkill.m_nEnhance);
                if (gss >= 0 )
                    end_time = t + (uint)gss;
                else
                    end_time = t + 6000;

                switch(pSkill.m_SkillBase.effect_type)
                {
/*
                    case 239:
                    case 268:
                        *(v5 - 124) = 0;
                        *(v5 - 120) = 0;
                        *(v5 - 116) = 0;
                        *(v5 - 4) = 0;
                        std::vector<int_std::allocator<int>>::reserve((v5 - 128), 7u);
                        *(v5 - 36) = _skill->m_pSkillBase->state_id;
                        std::vector<StructRoamer___std::allocator<StructRoamer__>>::push_back((v5 - 128), (v5 - 36));
                        v85 = 328;
                        do
                        {
                            v86 = _skill->m_pSkillBase;
                            *(v5 - 80) = *(&v86->uid + v85);
                            *(v5 - 76) = *(&v86->name_id + v85);
                            if ( *(v5 - 80) / 10000.0 != 0.0 )
                            {
                                *(v5 - 72) = *(&v86->uid + v85);
                                *(v5 - 68) = *(&v86->name_id + v85);
                                *(v5 - 36) = (*(v5 - 72) / 10000.0);
                                std::vector<StructRoamer___std::allocator<StructRoamer__>>::push_back((v5 - 128), (v5 - 36));
                            }
                            v85 += 8;
                        }
                        while ( v85 < 376 );
                        if ( *(v5 - 124) )
                        {
                            v87 = (*(v5 - 120) - *(v5 - 124)) >> 2;
                            if ( v87 )
                            {
                                v88 = XFastRandom(0, v87 - 1);
                                v89 = *std::vector<XLinearMemoryPool___std::allocator<XLinearMemoryPool__>>::operator__(
                                           (v5 - 128),
                                           v88);
                                v90 = _skill->m_pSkillBase;
                                v91 = v90->state_type;
                                v92 = *(v5 + 8);
                                v93 = *(v5 + 12);
                                v94 = SkillBase::GetStateLevel(v90, _skill->m_nRequestedSkillLevel, _skill->m_nEnhance);
                                v95 = (***(v5 + 16))();
                                *(v5 - 16) = StructCreature::AddState(
                                                 *(v5 + 20),
                                                 v91,
                                                 v89,
                                                 v95,
                                                 v94,
                                                 v93,
                                                 v92,
                                                 0,
                                                 0,
                                                 &unk_5F42BB) == 0;
                            }
                        }
                        *(v5 - 4) = -1;
                        std::vector<GameContent::REGEN_INFO_std::allocator<GameContent::REGEN_INFO>>::_Tidy((v5 - 128));
                        break;
*/

                    case 301:
                    case 302:
                    case 305:
                    case 306:
                        count = 5;
                       
                        if (pSkill.m_SkillBase.effect_type == 305 || pSkill.m_SkillBase.effect_type == 306 )
                            count = 0;
                        nLevel = pSkill.m_SkillBase.GetStateLevel(pSkill.m_nRequestedSkillLevel, pSkill.m_nEnhance);
                        if (count > 0)
                        {
                            for(i = -1; i < count; ++i)
                            {
                                
                                if (i >= 0 )
                                    stateCode = (State.StateCode)pSkill.m_SkillBase.m_var[i];
                                else
                                     stateCode = (State.StateCode) pSkill.m_SkillBase.state_id;
                                
                                if (stateCode != State.StateCode.None)
                                {
                                    bResult = pTarget.AddState((State.StateType)pSkill.m_SkillBase.state_type, stateCode, pCaster.m_hHandle,
                                        nLevel, t, end_time, false, 0, "") == 0;
                                }
                            }
                        }
                        break;

/*
                    case 307:
                        v26 = *(v5 + 20);
                        bResult = false;
                        v27 = 41;
                        while ( 1 )
                        {
                            v28 = *v26;
                            *(v5 - 80) = *(pSkill.m_SkillBase.uid + v27 * 8) / 10000.0;
                            *(v5 - 36) = (*(v28 + 208))(v26);
                            if ( *(v5 - 36) == *(v5 - 80) )
                                break;
                            ++v27;
                            if ( v27 >= 47 )
                                goto LABEL_89;
                        }
                        code = pSkill.m_nEnhance;
                        v29 = _skill->m_pSkillBase;
                        v113 = pSkill.m_nRequestedSkillLevel;
                        bResult = true;
                        v30 = pSkill.m_SkillBase.GetStateLevel(pSkill.m_nRequestedSkillLevel, pSkill.m_nEnhance);
                        *(v5 - 32) = -1;
                        v31 = *(v5 + 16);
                        *(v5 - 36) = v30;
                        *(v5 - 20) = 272;
                        do
                        {
                            v32 = _skill->m_pSkillBase;
                            if ( *(v5 - 32) >= 0 )
                                v33 = (*(&v32->uid + *(v5 - 20)) / 10000.0);
                            else
                                v33 = v32->state_id;
                            *(v5 - 24) = v33;
                            if ( v33 )
                            {
                                v34 = v32->state_type;
                                v35 = *(v5 + 8);
                                v36 = *(v5 + 12);
                                v37 = *(v5 - 36);
                                v38 = (**v31)(v31);
                                *(v5 - 16) = StructCreature::AddState(
                                                 *(v5 + 20),
                                                 v34,
                                                 *(v5 - 24),
                                                 v38,
                                                 v37,
                                                 v36,
                                                 v35,
                                                 0,
                                                 0,
                                                 &unk_5F42BB) == 0;
                            }
                            *(v5 - 20) += 8;
                            ++*(v5 - 32);
                        }
                        while ( *(v5 - 20) < 320 );
                        break;
*/
/*
                    case 308:
                        *(v5 - 24) = -1;
                        *(v5 - 36) = -24;
                        *(v5 - 20) = 272;
                        do
                        {
                            if ( *(v5 - 24) >= 0 )
                            {
                                v41 = _skill->m_pSkillBase;
                                v42 = *(v5 - 36);
                                code = _skill->m_nRequestedSkillLevel;
                                *(v5 - 32) = (*(&v41->uid + *(v5 - 20)) / 10000.0);
                                v43 = *(&v41->var[3].value + v42);
                                *(v5 - 56) = *(&v41->var[5].value + v42);
                                v44 = *(&v41->var[3].value + v42 + 4);
                                *(v5 - 52) = *(&v41->var[5].value + v42 + 4);
                                v45 = *(&v41->var[4].value + v42);
                                v46 = *(&v41->var[4].value + v42 + 4);
                                *(v5 - 76) = v44;
                                *(v5 - 44) = v46;
                                *(v5 - 48) = v45;
                                v47 = __PAIR__(*(v5 - 76), v43)
                                    + c_fixed<10000>::operator_<int>((v5 - 48), (v5 - 88), code)->value;
                                v48 = c_fixed<10000>::operator_<int>((v5 - 56), (v5 - 72), _skill->m_nEnhance);
                                v49 = LODWORD(v48->value);
                                v50 = (v47 + v48->value) >> 32;
                                *(v5 - 64) = v47 + v49;
                                *(v5 - 60) = v50;
                                v40 = (*(v5 - 64) / 10000.0);
                            }
                            else
                            {
                                code = _skill->m_nEnhance;
                                v39 = _skill->m_pSkillBase;
                                v113 = _skill->m_nRequestedSkillLevel;
                                *(v5 - 32) = v39->state_id;
                                v40 = SkillBase::GetStateLevel(v39, v113, code);
                            }
                            if ( *(v5 - 32) )
                            {
                                if ( v40 )
                                {
                                    v51 = _skill->m_pSkillBase->state_type;
                                    v52 = *(v5 + 8);
                                    v53 = *(v5 + 12);
                                    v54 = v40;
                                    v55 = (***(v5 + 16))();
                                    *(v5 - 16) = StructCreature::AddState(
                                                     *(v5 + 20),
                                                     v51,
                                                     *(v5 - 32),
                                                     v55,
                                                     v54,
                                                     v53,
                                                     v52,
                                                     0,
                                                     0,
                                                     &unk_5F42BB) == 0;
                                }
                            }
                            *(v5 - 20) += 8;
                            ++*(v5 - 24);
                            *(v5 - 36) += 24;
                        }
                        while ( *(v5 - 20) < 304 );
                        break;
*/
/*
                        case 309:
                            *(v5 - 20) = 0;
                            v56 = 0;
                            do
                            {
                                if ( *(v5 - 20) >= v56 )
                                {
                                    v58 = _skill->m_pSkillBase;
                                    v59 = _skill->m_nRequestedSkillLevel;
                                    v60 = LODWORD(v58->var[1].value);
                                    *(v5 - 32) = (v58->var[0].value / 10000.0);
                                    *(v5 - 56) = LODWORD(v58->var[3].value);
                                    *(v5 - 52) = HIDWORD(v58->var[3].value);
                                    *(v5 - 64) = LODWORD(v58->var[2].value);
                                    *(v5 - 60) = HIDWORD(v58->var[2].value);
                                    *(v5 - 84) = HIDWORD(v58->var[1].value);
                                    v61 = __PAIR__(*(v5 - 84), v60)
                                        + c_fixed<10000>::operator_<int>((v5 - 64), (v5 - 96), v59)->value;
                                    v62 = c_fixed<10000>::operator_<int>((v5 - 56), (v5 - 104), _skill->m_nEnhance);
                                    v63 = LODWORD(v62->value);
                                    v64 = (v61 + v62->value) >> 32;
                                    *(v5 - 48) = v61 + v63;
                                    *(v5 - 44) = v64;
                                    code = _skill->m_nRequestedSkillLevel;
                                    *(v5 - 36) = (*(v5 - 48) / 10000.0);
                                    v65 = _skill->m_pSkillBase;
                                    v66 = LODWORD(v65->var[4].value);
                                    v67 = HIDWORD(v65->var[4].value);
                                    *(v5 - 72) = LODWORD(v65->var[6].value);
                                    *(v5 - 68) = HIDWORD(v65->var[6].value);
                                    *(v5 - 28) = LODWORD(v65->var[5].value);
                                    *(v5 - 24) = HIDWORD(v65->var[5].value);
                                    v69 = c_fixed<10000>::operator_<int>((v5 - 28), (v5 - 112), code)->value + __PAIR__(v67, v66);
                                    HIDWORD(v68) = HIDWORD(v69);
                                    v70 = c_fixed<10000>::operator_<int>((v5 - 72), (v5 - 120), _skill->m_nEnhance);
                                    LODWORD(v68) = LODWORD(v70->value);
                                    v71 = __PAIR__(HIDWORD(v70->value), v69) + v68;
                                    *(v5 - 76) = (__PAIR__(HIDWORD(v70->value), v69) + v68) >> 32;
                                    *(v5 - 80) = v71;
                                    *(v5 + 8) = (*(v5 - 80) / 10000.0 * 100.0 + *(v5 + 12));
                                    v56 = 0;
                                }
                                else
                                {
                                    code = _skill->m_nEnhance;
                                    v57 = _skill->m_pSkillBase;
                                    v113 = _skill->m_nRequestedSkillLevel;
                                    *(v5 - 32) = v57->state_id;
                                    *(v5 - 36) = SkillBase::GetStateLevel(v57, v113, code);
                                }
                                if ( *(v5 - 32) != v56 )
                                {
                                    if ( *(v5 - 36) != v56 )
                                    {
                                        if ( *(v5 + 8) > *(v5 + 12) )
                                        {
                                            v72 = _skill->m_pSkillBase->state_type;
                                            v73 = *(v5 + 8);
                                            v74 = *(v5 + 12);
                                            v75 = *(v5 - 36);
                                            v76 = (***(v5 + 16))();
                                            *(v5 - 16) = StructCreature::AddState(
                                                             *(v5 + 20),
                                                             v72,
                                                             *(v5 - 32),
                                                             v76,
                                                             v75,
                                                             v74,
                                                             v73,
                                                             v56,
                                                             v56,
                                                             &unk_5F42BB) == 0;
                                        }
                                    }
                                }
                                ++*(v5 - 20);
                            }
                            while ( *(v5 - 20) < 2 );
                            break;
*/
                    case 314:
                        nLevel = pSkill.m_SkillBase.GetStateLevel(pSkill.m_nRequestedSkillLevel, pSkill.m_nEnhance);
                        stateCode = (State.StateCode)pSkill.m_SkillBase.state_id;

                        if (stateCode != State.StateCode.None)
                        {
                            bResult = pTarget.AddState((State.StateType)pSkill.m_SkillBase.state_type, stateCode, pCaster.m_hHandle,
                                nLevel, t, end_time, false, 0, "") == 0;
                        }
                        break;


                    default:
                        if (pSkill.m_SkillBase.effect_type != 701 )
                        {
                            if (pSkill.m_SkillBase.effect_type != 702 )
                            {
                                if (!pCaster.IsSameObject(pTarget)
                                  || pSkill.m_SkillBase.effect_type != 121 
                                  && pSkill.m_SkillBase.effect_type != 221 
                                  && pSkill.m_SkillBase.effect_type != 235 
                                  && pSkill.m_SkillBase.effect_type != 266 
                                  && pSkill.m_SkillBase.effect_type != 30002)
                                {
                                    bResult = pTarget.AddState((State.StateType)pSkill.m_SkillBase.state_type,(State.StateCode)pSkill.m_SkillBase.state_id,
                                        pCaster.m_hHandle,pSkill.m_SkillBase.GetStateLevel(pSkill.m_nRequestedSkillLevel, pSkill.m_nEnhance),
                                        t,end_time,false,0,"") == 0;
                                }
                            }
                        }
                        break;


                }

            LABEL_89:
                if (pSkill.m_SkillBase.uid != 6008 )
                {
                    if (pSkill.m_SkillBase.uid != 6009 )
                    {
                        if (pSkill.m_SkillBase.uid != 6010 )
                        {
                            if (pTarget.IsMonster() && pTarget.IsEnemy(pCaster, true))
                            {
                                (pTarget as Monster).AddHate(pCaster.m_hHandle,1, true, true);
                            }
                            else if (pTarget.IsNPC())
                            {
                                if (pTarget.IsEnemy(pCaster, false))
                                    (pTarget as NPC).SetAttacker(pCaster);
                            }
                        }
                    }
                }

            }

            GameContent.AddSkillResult(this.pvList, bResult, 10, pTarget.m_hHandle);
            return true;
        }

        public List<SkillResult> pvList;
    }



}

